﻿using System.Collections.Frozen;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Data;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input;
using FanaticRock.AudioManage.Helpers;
using FanaticRock.Core.DI;
using FanaticRock.Core.Enums;
using FanaticRock.Core.Extensions;
using FanaticRock.Core.Interfaces;
using FanaticRock.Core.Models;
using FanaticRock.Core.ServiceInterfaces;
using FanaticRock.Extensions;
using FanaticRock.Helpers;
using FanaticRock.MediaSource.BilibiliAPI.Interfaces;
using FanaticRock.ViewModels.OptionSettingConfig;

namespace FanaticRock.ViewModels
{
    [INotifyPropertyChanged]
    [InjectMe]
    public partial class MainViewModel : ILogger
    {
        #region dependency

        private ISongProviderService _songProviderService;
        private IAudioPlayService _audioPlayService;
        private IPlayListService _playListService;
        private IBilibiliCookieService _bilibiliCookieService;
        private IDownloadManageService _downloadManageService;
        private ILocalDbService _localDbService;

        #endregion

        #region props

        [ObservableProperty]
        private ObservableCollection<SongViewModel> _songs = new ObservableCollection<SongViewModel>();

        [ObservableProperty]
        private CollectionViewSource _songViewSource = new CollectionViewSource();

        [ObservableProperty]
        private ObservableCollection<SongViewModel> _songsInPlayList = new ObservableCollection<SongViewModel>();

        [ObservableProperty]
        private DisplaySongViewModel _currentDisplaySong = new DisplaySongViewModel();

        [ObservableProperty]
        private OptionSettingConfigViewModel _optionSettingConfig;

        public PlayModeEnum PlayModeEnum { get => _playModeEnum; set { SetPlayModeEnum(value); } }
        private PlayModeEnum _playModeEnum;

        [ObservableProperty]
        private TimeSpan _progress;

        [ObservableProperty]
        private TimeSpan _totalDuration;

        [ObservableProperty]
        private bool _isPlaying = false;

        [ObservableProperty]
        private bool _isSliderPressed = false;

        public double Volume { get => _volume; set => SetVolume(value); }
        private double _volume = 0.5;

        #endregion

        #region ctors

        public MainViewModel(ISongProviderService songProviderService,
                             IAudioPlayService audioPlayService,
                             IPlayListService playListService,
                             IBilibiliCookieService bilibiliCookieService,
                             IDownloadManageService downloadManageService,
                             ILocalDbService localDbService)
        {

            _songProviderService = songProviderService;
            _audioPlayService = audioPlayService;
            _playListService = playListService;
            _bilibiliCookieService = bilibiliCookieService;
            _downloadManageService = downloadManageService;
            _localDbService = localDbService;

            _audioPlayService.AudioProgressUpdated += _audioPlayService_AudioProgressUpdated;
            _playListService.PlayListChanged += _playListService_PlayListChanged;
            _playListService.AudioPlayed += _playListService_AudioPlayed;
            _downloadManageService.DownloadProgress += _downloadManageService_DownloadProgress;
            _downloadManageService.DownloadCompleted += _downloadManageService_DownloadCompleted;

            _optionSettingConfig = new OptionSettingConfigViewModel(_localDbService);

            InitDownloadList();
            InitDownloadListPart();

            var songModels = songProviderService.GetSongs();

  
            Songs = ObservableCollectionHelper.CreateFromModel<Song, SongViewModel>(songModels)
                                              .UpdateIndex();


            _songViewSource = new CollectionViewSource() { Source = Songs };
            _songViewSource.Filter += _songView_Filter;


            SongsInPlayList = ObservableCollectionHelper.CreateFromModel<Song, SongViewModel>(playListService.PlayList)
                                                        .UpdateIndex();


            Volume = audioPlayService.GetVolume();

            PropertyChanged += MainViewModel_PropertyChanged;

        }


        private void _songView_Filter(object sender, FilterEventArgs e)
        {
            //if (e.Item is SongViewModel songViewModel)
            //{
            //    e.Accepted = songViewModel.IndexInCollection < 30;
            //}
        }

        #endregion

        #region event impls

        private void MainViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(IsSliderPressed))
            {
                this.Info($"MainViewModel.MainViewModel_PropertyChanged: IsSliderPressed {_isSliderPressed}");
                if (_isSliderPressed == false)
                {
                    OnLeaveDragSlider();
                }
            }
        }

        private void OnLeaveDragSlider()
        {
            _audioPlayService.SetPosition(_progress);
        }


        // 播放进度更新。
        private void _playListService_PlayListChanged(object? sender, Core.AudioPlay.Events.PlayListChangedEventArgs e)
        {
            Application.Current.Dispatcher.Invoke(() =>
            {
                _playListService_PlayListChangedCore(sender, e);
            });
        }

        private void _playListService_PlayListChangedCore(object? sender, Core.AudioPlay.Events.PlayListChangedEventArgs e)
        {
            var playListService = sender as IPlayListService;
            if (playListService == null) return;

            switch (e.Action)
            {
                case System.ComponentModel.CollectionChangeAction.Add:
                    {
                        var songViewModels = e.NewItems.Select(s => new SongViewModel(s));
                        SongsInPlayList.AddRange(songViewModels);
                        break;
                    }

                case System.ComponentModel.CollectionChangeAction.Remove:
                    {
                        var currentSongViewModelDictionary = SongsInPlayList.ToFrozenDictionary(s => s.Id);
                        foreach (var item in e.OldItems)
                        {
                            var songId = item.Id;
                            if (currentSongViewModelDictionary.TryGetValue(songId, out var existSongViewModel))
                            {
                                SongsInPlayList.Remove(existSongViewModel);
                            }
                        }
                        break;
                    }

                case System.ComponentModel.CollectionChangeAction.Refresh:
                    {
                        SongsInPlayList.Clear();
                        break;
                    }

                default:
                    break;
            }
        }

        private void _playListService_AudioPlayed(object? sender, Core.AudioPlay.Events.AudioPlayedEventArgs e)
        {
            CurrentDisplaySong = new DisplaySongViewModel(e.Song);
        }

        private void _audioPlayService_AudioProgressUpdated(object? sender, Core.AudioPlay.Events.AudioProgressUpdateEventArgs e)
        {
            if (IsSliderPressed == true) return;

            Progress = e.CurrentPosition;
            TotalDuration = e.TotalDuration;

            if (e.State == Core.AudioPlay.AudioPlayStateEnum.Playing)
            {
                IsPlaying = true;
            }
            else if (e.State == Core.AudioPlay.AudioPlayStateEnum.Paused)
            {
                IsPlaying = false;
            }
        }


        #endregion

        #region commands

        [RelayCommand]
        private void SwitchNextPlayMode()
        {
            var nextModeEnum = PlayModeEnumHelper.GetNextMode(_playModeEnum);
            SetPlayModeEnum(nextModeEnum);
        }

        [RelayCommand]
        private void Play()
        {
            _playListService.Play();
        }

        [RelayCommand]
        private void PlayNext()
        {
            _playListService.PlayNext();
        }


        [RelayCommand]
        private void PlayPreview()
        {
            _playListService.PlayPreview();
        }

        [RelayCommand]
        private void Pause()
        {
            _playListService.Pause();
        }

        [RelayCommand]
        private void ClearSongsInPlayList()
        {
            _playListService.Clear();
        }

        #endregion

        #region methods

        private void SetVolume(double value)
        {
            _volume = value;
            OnPropertyChanged(nameof(Volume));
            _audioPlayService.SetVolume(value);
        }


        private void SetPlayModeEnum(PlayModeEnum value)
        {
            _playModeEnum = value;
            _playListService.SetPlayModeEnum(value);
            OnPropertyChanged(nameof(PlayModeEnum));
        }

        #endregion

        #region singleton

        private static Lazy<MainViewModel> _instance = new Lazy<MainViewModel>(CreateSingleton);
        public static MainViewModel Instance => _instance.Value;

        private static MainViewModel CreateSingleton()
        {
            return Ioc.Default.GetService<MainViewModel>();
        }

        #endregion
    }
}
